/**
 * @particulars 工具函数
 */

// 2、维护一个全局的对象，对Vue 及其组件的选项进行合并，优先子组件所拥有的选项
const strats = {};
const LIFECYCLE = ['beforeCreate', 'created'];

// 采用策略模式，对生命周期等进行处理
LIFECYCLE.forEach(hook => {
  // 循环挂载生命周期钩子，将生命周期维护在队列里，【父组件的生命周期、子组件的生命周期】
  strats[hook] = function (parent, child) {
    if (child) {
      if (parent) {
        // 如果儿子有，父亲也有，将两者合并到数组中
        return parent.concat(child);
      } else {
        // 儿子有，父亲没有，则将儿子包装成数组
        return [child];
      }
    } else {
      // 如果没有儿子，则直接返回父亲
      return parent;
    }
  }
})

// 挂载components，让父子组件的选项建立联系
strats.components = function (parentVal, childVal) {
  // 创建一个对象，将parentVal 作为新对象的原型
  const res = Object.create(parentVal);

  // 如果有子组件选项，则将子项挂载到以父对象为原型的对象上
  /**
   * {
   *   child-button: {......}
   *   [[prototype]]: { parent-button: {......} }
   * }
   */
  if (childVal) {
    for (let key in childVal) {
      // 返回的是构造的对象，可以拿到原型上父亲的属性，同时将儿子的属性也拷贝一份到自己上
      res[key] = childVal[key];
    }
  }

  return res;
}


// 1、合并选项，将父级的选项和子级的选项进行合并
export function mergeOptions(parent, child) {
  const options = {};

  // 合并父级选项
  for (let key in parent) {
    mergeField(key);
  }

  // 合并子组件选项
  for (let key in child) {
    // 如果父级已经有了该选项，则子级不对其进行合并
    if (!parent.hasOwnProperty(key)) mergeField(key);
  }

  // 合并选项字段
  function mergeField(key) {
    // 如果策略里面有，则采用策略模式进行合并，对该选项进行特殊处理（components、beforeCreate、created......）
    if (strats[key]) {
      // 选项挂载对应策略函数处理后的对象，建立父子关系
      options[key] = strats[key](parent[key], child[key]);
    } else {
      // 否则优先使用子级的选项
      options[key] = child[key] || parent[key];
    }
  }

  return options;
}